Conversation
|
Looks good, thanks for implementing it (so quickly as well!). My comments are just questions for clarification.
|
| if verbose: | ||
| print(' => N_eff > %d : shared gaussian shape %r (rel=%.6f) shared by [%s]' | ||
| % (threshold, variation, rel, ', '.join(nominal.keys()))) | ||
| for p in nominal: |
There was a problem hiding this comment.
If we set a condition for calling _make_mcstat_template to something like alpha < alpha_min, it would prevent the creation of, and adding to the ledger, variation histograms for nuisances that have negligible impact. Correct?
There was a problem hiding this comment.
That is correct, but I thought about this while writing the implementation and I'm not sure we can use alpha itself as a criteria for dropping bins from the MC statistical uncertainty treatment.
alpha is defined as
So we have:
alpha = e**2/n_tot = w (the per-event weight)
N_eff = n_tot/alpha (effective number of MC events)
I can't immediately see a sensible value for alpha_min that would allow us to gauge the impact of a process. What do you think ?
I think a better treatment than using alpha on its own would be to compare the MC background processes to the data-driven background process. Then one would ignore bins in which the MC backgrounds contribute to the total background by a much smaller fraction than the data-driven background. This would then govern the "impact" of the MC process. What do you think?
There was a problem hiding this comment.
At alpha= 1/x, we have x times more MC events than their yield. The MC stat. uncert. is sqrt(x) times lower than the expected Poisson uncertainty of observed yield from these processes. At sufficiently high (low) x (alpha), MC stat. uncert. becomes negligible.
Moreover, most of our backgrounds typically comes from the data-driven estimate. The expected Poisson uncertainty of the observed data then includes a contribution from that as well. The threshold then depends on the analysis.
A first attempt at implementing automatic MC statistical uncertainties, à la Combine.
I followed the Combine implementation outlined here.
Combine handles automatic MC stats by using
text2workspace.py, which parses the datacard and finds all TH1 objects and creates aRooRealVarobject for allparamobjects in the card. These objects get attached a Gaussian constraint and are treated as a nuisance parameter. Notably, this only works forRooWorkspaceobjects that do not containRooDataHists. This disqualifies 2DAlphabet workspaces from usingautomcstats, since we use 2D RooDataHists.I think that enabling something like what Combine does using
paramsin the datacard would necessitate a very difficult re-write of the Combine code, so this implementation uses a more naive approach. During workspace creation, when building theOrganizedHistobject, 2DAlphabet will now loop over all nominal background histograms in each region (signal can be included as well, though I don't see why one would want to). The algorithm follows Combine's implementation:(bx, by)of the 2D histogram.The resulting histograms are identical to the nominal background histograms except for the given bin, which is shifted up or down by some scaling factor governed by the number of events.
Case 1:$n_\text{tot}^\text{eff} > n^\text{threshold}$
In this case, we are creating a single nuisance parameter that scales the total yield in the bin. To accomplish this, I use the following logic:
Each process$i$ in this bin gets its nominal yield $n_i$ scaled by $1\pm \text{r}$ , where the "down" variation is bounded at 0. For this case, $r = e_\text{tot} / n_\text{tot}$ . Thus, in this bin, process $i$ contributes $n_i * (1 + \nu * r)$ , where $\nu$ is the value of the (Gaussian-constrained) nuisance parameter. For all processes in this bin, we then obtain:
Since$e_\text{tot} = \sqrt{\sum_i e_i^2}$ , we get the combined MC stat uncertainty in this given bin. And, since $\nu$ is shared for all processes in this bin, a single nuisance parameter controls the yields of all processes in this bin.
Usage
The user does not have to do anything special, I've enabled 2DA to use "autoMCstats" by default. The method can be turned off, its threshold modified, or signals included in the calculation, by modifying the JSON:
Other than that, no change needs to be made to the user's 2DAlphabet python script or JSON config file. Note that this will produce at least
N * R * 2new histograms, whereNis the number of processes,Ris the number of regions (pass, fail, etc), and2is for up/down. There may be more histograms if the BB-lite threshold is not met in a given bin.Testing
I've tested this with some simple dummy histograms simulating$X \to H(b\bar{b}) Y(b\bar{b})$ in a Fail and Pass region and 2D histograms of data, a single signal, and Zbb and Hbb backgrounds. The testing workspace can be recreated with the following files:
test.tar.gz
The tarball contains:
passandfailregions, all processes, and the two shape systematics. The JSON also contains anOPTIONSsection that customizes the mcstats optionsTesting results
By default, I have 2DAlphabet give verbose output when creating the mcstat nuisances. The output is more or less copied entirely from combine. Here's the example output when creating the workspace:
One can already see two examples of the MC stat functionality working for cases where (1) the$n_\text{tot}^\text{eff}$ is above threshold and (2) it is below the threshold. In the former case a shared parameter is created and in the latter separate parameters are created per-process.
One can also see that signal is excluded from this calculation and from MC statistical uncertainties, as per the JSON options.
We can also look at the post-fit results for the fits with and without MC statistical uncertainties, using a constant transfer function for the QCD estimate. All other fit options are the same between the two cases. In the former, the pulls are noticeably smaller, indicating that the fit is making use of the additional freedom provided by the MC statistical uncertainty parameters.
mX projection:


mY projection:

